package online.view.el;

import java.beans.FeatureDescriptor;
import java.util.Collections;
import java.util.Iterator;
import java.util.Map;

import javax.el.ELContext;
import javax.el.ELResolver;
import javax.servlet.jsp.JspContext;
import javax.servlet.jsp.PageContext;

import online.view.ViewUtil;
import online.view.model.ViewMap;

/**
 * ELリゾルバ
 *
 * @author Tadashi Nakayama
 */
public final class ViewELResolver extends ELResolver {

	/**
	 * @see javax.el.ELResolver#getCommonPropertyType(javax.el.ELContext, java.lang.Object)
	 */
	@Override
	public Class<?> getCommonPropertyType(final ELContext context, final Object base) {
		if (base == null) {
			return Map.class;
		}
		return null;
	}

	/**
	 * @see javax.el.ELResolver#getFeatureDescriptors(javax.el.ELContext, java.lang.Object)
	 */
	@Override
	public Iterator<FeatureDescriptor> getFeatureDescriptors(
			final ELContext context, final Object base) {
		return Collections.EMPTY_LIST.iterator();
	}

	/**
	 * @see javax.el.ELResolver#getType(javax.el.ELContext, java.lang.Object, java.lang.Object)
	 */
	@Override
	public Class<?> getType(final ELContext context, final Object base, final Object property) {
		return Object.class;
	}

	/**
	 * @see javax.el.ELResolver#getValue(javax.el.ELContext, java.lang.Object, java.lang.Object)
	 */
	@Override
	public Object getValue(final ELContext context, final Object base, final Object property) {
		if (String.class.isInstance(property)) {
			if (base == null || ViewMap.class.isInstance(base)) {
				PageContext page = PageContext.class.cast(context.getContext(JspContext.class));
				ViewMap map = getViewMap(page, base);
				if (map != null) {
					String key = String.class.cast(property);
					if ("band".equals(key)) {
						context.setPropertyResolved(true);
						return new Band(map);
					} else if (page.getAttributesScope(key) == 0 || map.containsKey(key)) {
						context.setPropertyResolved(true);
						return map.get(key);
					}
				}
			} else if (Band.class.isInstance(base)) {
				context.setPropertyResolved(true);
				ViewMap map = Band.class.cast(base).getViewMap();
				if (ViewMap.class.isInstance(map.get(property))) {
					return new Band(ViewMap.class.cast(map.get(property)));
				}
				return new BandList(map, String.class.cast(property));
			}
		}
		return null;
	}

	/**
	 * ViewMap取得
	 * @param page PageContext
	 * @param base Baseオブジェクト
	 * @return ViewMap
	 */
	private ViewMap getViewMap(final PageContext page, final Object base) {
		if (page != null) {
			if (base != null) {
				return ViewMap.class.cast(base);
			}
			return ViewMap.class.cast(page.findAttribute(ViewUtil.ATTR_MAP));
		}
		return null;
	}

	/**
	 * @see javax.el.ELResolver#isReadOnly(javax.el.ELContext, java.lang.Object, java.lang.Object)
	 */
	@Override
	public boolean isReadOnly(final ELContext context, final Object base, final Object property) {
		return true;
	}

	/**
	 * @see javax.el.ELResolver
	 * #setValue(javax.el.ELContext, java.lang.Object, java.lang.Object, java.lang.Object)
	 */
	@Override
	public void setValue(final ELContext context, final Object base,
			final Object property, final Object value) {
		return;
	}

	/**
	 * バンド
	 *
	 * @author Tadashi Nakayama
	 */
	private static final class Band {
		/** ViewMap */
		private final ViewMap vm;

		/**
		 * コンストラクタ
		 * @param val ViewMap
		 */
		public Band(final ViewMap val) {
			this.vm = val;
		}

		/**
		 * ViewMap取得
		 * @return ViewMap
		 */
		public ViewMap getViewMap() {
			return this.vm;
		}
	}
}
